home *** CD-ROM | disk | FTP | other *** search
- /* sendbatch.c - simple sendbatch for mnews + taylor uucp.
- * pipes the articles thru compress/freeze and into uux directly
- * so that it needs no tempfile.
- * (the original `sbatch' i had doesn't run under MiNT so i needed
- * a new one. :-)
- *
- * send bugs + comments to: Juergen Lock <nox@jelal.north.de>
- *
- */
-
- #define SYS_UUX "/usr/local/bin/uux.ttp", "uux", "-rjg", "d", "-", uuxcmd
- #define BATCH_DIR "/usr/spool/batch/%s"
-
- /* uux command (execl args) to send the batch to. the uuxcmd arg will be
- replaced with system!rnews or system2!rfnews (or frnews) */
- #ifndef SYS_UUX
- #define SYS_UUX "/usr/local/bin/uux.ttp", "uux", "-rjg", "d", "-", uuxcmd
- #endif
-
- /* directory where the batch files live, %s is the system name */
- #ifndef BATCH_DIR
- #define BATCH_DIR "/usr/spool/batch/%s"
- #endif
-
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <fcntl.h>
- #include <ctype.h>
- #include <stat.h>
- #include <process.h>
- #include <signal.h>
- #include <unistd.h>
- #include <errno.h>
-
- /* make sure we have EX_TEMPFAIL */
- #ifndef EX_TEMPFAIL
- #define EX_TEMPFAIL 75
- #endif
-
- /* write end of the pipe to compress/freeze or (if no compression) uux.
- (global so it can easily be closed on errors.) */
- int pfd;
-
- /* pid of the exec'd compress or freeze, if any */
- int cpid;
- /* exit code */
- int cret;
-
- /* pid of uux */
- int upid;
- /* and its exit code */
- int uret;
-
- /* wait for a child. always check the pid because we usually don't
- know wich one dies first. */
- void cwait ()
- {
- int status, pid, wait ();
-
- pid = wait (&status);
- if (pid == cpid) {
- cret = status >> 8;
- cpid = 0;
- } else if (pid == upid) {
- uret = status >> 8;
- upid = 0;
- }
- }
-
- /* print error message, cleanup and exit. */
- void fail (ex, msg)
- int ex;
- char *msg;
- {
- void closepipe ();
-
- if (msg)
- fprintf (stderr, "sendbatch: %s\n", msg);
- closepipe (1);
- exit (ex);
- }
-
- /* close pipe and wait for childs. if err is 0 check exit codes, else
- return right away because we're called from within the error handler
- already. */
- void closepipe (err)
- int err;
- {
- if (err && upid > 0) {
- /* give processes a chance to die on their own... */
- sleep (1);
- /* else tell uux to forget the current batch. */
- kill (upid, SIGTERM);
- }
- if (pfd) {
- close (pfd);
- pfd = 0;
- }
- if (cpid > 0)
- cwait ();
- if (upid > 0)
- cwait ();
- if (err)
- return;
- if (uret)
- fail (uret, (char *) NULL);
- if (cret)
- fail (cret, "compress or freeze failed");
- }
-
- /* open a pipe to uux that goes thru ccmd with args in cargs. if chead
- is != NULL it is sent to uux before ccmd is spawned. if ccmd is NULL
- the pipe will go to uux without compression. returns the pipe (fd). */
- int openpipe (uuxcmd, ccmd, cargs, chead)
- char *uuxcmd;
- char *ccmd;
- char *cargs;
- char *chead;
- {
- int upipefd[2], cpipefd[2];
-
- /* first spawn uux... */
- if (pipe (upipefd) < 0 || (upid = fork()) < 0)
- fail (EX_TEMPFAIL, "pipe or fork failed. (not enough memory?)");
-
- if (!upid) {
- /* child */
-
- /* close write end of the pipe */
- close (upipefd[1]);
- /* connect uux' stdin to the pipe */
- if (dup2 (upipefd[0], 0) < 0)
- exit (EX_TEMPFAIL);
- close (upipefd[0]);
- /* ...and exec it. (uuxcmd is used in SYS_UUX) */
- execl (SYS_UUX, (char *) NULL);
- /* exec failed, probably also temporary. */
- perror ("uux");
- exit (EX_TEMPFAIL);
- }
- /* parent */
-
- /* close read end */
- close (upipefd[0]);
-
- if (!ccmd)
- /* no compression, return the pipe to uux. */
- return upipefd[1];
-
- /* if we should write a `#! [cf]unbatch' header do so now */
- if (chead)
- write (upipefd[1], chead, strlen (chead));
-
- /* spawn the compress/freeze */
- if (pipe (cpipefd) < 0 || (cpid = fork()) < 0) {
- /* set pfd so it will get closed */
- pfd = upipefd[1];
- fail (EX_TEMPFAIL, "pipe or fork failed. (not enough memory?)");
- }
-
- if (!cpid) {
- /* child */
-
- /* close write end of the pipe */
- close (cpipefd[1]);
- /* connect stdin and stdout to the pipes */
- if (dup2 (cpipefd[0], 0) < 0 || dup2 (upipefd[1], 1) < 0)
- exit (EX_TEMPFAIL);
- close (cpipefd[0]);
- close (upipefd[1]);
- /* ...and exec. */
- execlp (ccmd, ccmd, cargs, (char *) NULL);
- /* exec failed, probably also temporary. */
- perror (ccmd);
- exit (EX_TEMPFAIL);
- }
- /* parent */
-
- /* close read end */
- close (cpipefd[0]);
- /* close pipe to uux */
- close (upipefd[1]);
-
- /* return pipe to compress/freeze */
- return cpipefd[1];
- }
-
- /* dummy SIGPIPE handler... */
- void dummy (sig)
- int sig;
- {
- /* do nothing because write will return -1 anyway. */
- }
-
- int main (argc, argv)
- int argc;
- char **argv;
- {
- static char buf [0x4000];
- char ch, *command = "rnews", uuxcmd[20], cargs[10];
- int rfnews = 0, uncompressed = 0, freeze = 0, verbose = 0, maxbits = 0;
- long maxbatch = 100000, written = 0;
- char fname[FILENAME_MAX], article[FILENAME_MAX];
- FILE *fp;
-
- char *optstr = "ub:rfm:v";
- extern char *optarg;
- extern int optind;
-
- while ((ch = getopt(argc, argv, optstr)) != EOF) {
- switch (ch) {
- case 'u': uncompressed = 1; break;
- case 'b': if (isdigit(*optarg))
- maxbits = atoi(optarg);
- break;
- case 'r': if (freeze)
- command = "frnews";
- else
- command = "rfnews";
- rfnews = 1; break;
- case 'f': freeze = 1; break;
- case 'm': if (isdigit(*optarg))
- maxbatch = 0x400 * atoi(optarg);
- break;
- case 'v': ++verbose; break;
- default: goto usage;
- }
- }
- if (argc <= optind || argc > optind + 1 ||
- (freeze && uncompressed) || (rfnews && !freeze)) {
- usage:
- fprintf (stderr,
- "usage: sendbatch [-u|-f|-rf|-fr] [-b maxbits] [-m maxkperbatch] [-v] site\n\n"
- "-u: send uncompressed batch\n"
- "-f: use freeze instead of compress\n"
- "-rf: ditto but send to rfnews and without a `#! funbatch' header\n"
- "-fr: same but frnews instead or rfnews\n"
- "-b: -b arg to compress (default = none, use compress' default)\n"
- "-m: maximum size (Kbytes) of a single batch before compression,\n"
- " more data will be split into multiple batches as long as no\n"
- " single article is longer. (default = 100)\n"
- "-v verbose (not yet.)\n");
- exit (1);
- }
-
- sprintf (uuxcmd, "%s!%s", argv[optind], command);
- if (maxbits)
- sprintf (cargs, "-b%d", maxbits);
-
- /* try open the batch file */
- sprintf (fname, BATCH_DIR, argv[optind]);
-
- if (!(fp = fopen (fname, "r"))) {
- /* if its just not there then we're finished */
- if (errno == ENOENT)
- exit (0);
- perror (fname);
- exit (1);
- }
-
- /* catch and ignore SIGPIPE. (we check the result of the write()
- calls so ignoring is ok.) can't use SIG_IGN because then our
- childs would ignore SIGPIPE also... */
- signal (SIGPIPE, dummy);
-
- /* read thru the file, open each article and send it down the pipe */
- while (fgets (article, sizeof article, fp)) {
- char line[30], *p;
- int count, fd;
- struct stat st;
-
- if (*(p = article + strlen (article) - 1) == '\n')
- *p = 0;
- if ((fd = open (article, O_RDONLY)) < 0 || fstat (fd, &st) < 0)
- fail (1, strerror (errno));
-
- /* make sure it wouldn't make the current batch too large */
- if (pfd && written + st.st_size + sizeof "#! rnews 1234567890\n" > maxbatch) {
- closepipe (0);
- written = 0;
- }
-
- /* open the next batch if necessary */
- if (!pfd)
- pfd = openpipe (uuxcmd, uncompressed ? (char *) NULL :
- (freeze ? "freeze" : "compress"),
- maxbits ? cargs : (char *) NULL,
- (rfnews || uncompressed) ? (char *) NULL :
- (freeze ? "#! funbatch\n" : "#! cunbatch\n"));
-
- /* write the #! rnews... */
- sprintf (line, "#! rnews %ld\n", st.st_size);
- write (pfd, line, count = strlen (line));
- written += count;
-
- /* ...and copy the article. */
- while ((count = read (fd, buf, sizeof buf)) > 0) {
- if (write (pfd, buf, count) != count) {
- close (fd);
- fail (1, strerror (errno));
- }
- written += count;
- }
- if (close (fd) < 0 || count < 0)
- fail (1, strerror (errno));
- }
-
- if (ferror (fp) || fclose (fp))
- fail (1, strerror (errno));
- if (pfd)
- closepipe (0);
-
- unlink (fname);
- exit (0);
- }
-